using ColorFillGame.Domain.Entities;
using ColorFillGame.Domain.Exceptions;
using ColorFillGame.Domain.Repositories;
using ColorFillGame.Domain.Services;
using ColorFillGame.Domain.ValueObjects;
using MediatR;

namespace ColorFillGame.Application.Commands.Game;

public class JoinGameCommandHandler : IRequestHandler<JoinGameCommand, Guid>
{
    private readonly IGameRepository _gameRepository;
    private readonly IPlayerRepository _playerRepository;
    private readonly IGameService _gameService;

    public JoinGameCommandHandler(
        IGameRepository gameRepository,
        IPlayerRepository playerRepository,
        IGameService gameService)
    {
        _gameRepository = gameRepository;
        _playerRepository = playerRepository;
        _gameService = gameService;
    }

    public async Task<Guid> Handle(JoinGameCommand request, CancellationToken cancellationToken)
    {
        // 获取游戏
        var game = await _gameRepository.GetByIdAsync(request.GameId);
        if (game == null)
            throw new GameNotFoundException(request.GameId);

        // 检查游戏是否已经开始
        if (game.Status == GameStatus.InProgress)
            throw new GameAlreadyStartedException(request.GameId);

        // 检查游戏是否已满
        if (game.Players.Count >= game.MaxPlayers)
            throw new GameRoomFullException(request.GameId);

        // 检查玩家是否已存在
        var existingPlayer = await _playerRepository.GetByConnectionIdAsync(request.ConnectionId);
        if (existingPlayer != null && existingPlayer.GameId == request.GameId)
            throw new PlayerAlreadyExistsException(existingPlayer.Id);

        // 创建新玩家（不在这里分配颜色，让Game.AddPlayer处理）
        var player = new Player(Guid.NewGuid(), request.PlayerName, request.GameId);
        player.SetConnectionId(request.ConnectionId);

        // 将玩家添加到游戏对象（这里会自动分配颜色）
        _gameService.JoinGame(game, player);
        
        Console.WriteLine($"Player {player.Name} joined game {game.Id} with color {player.Color?.Name ?? "None"}");
        
        // 然后保存玩家和游戏
        await _playerRepository.AddAsync(player);
        await _playerRepository.SaveChangesAsync();
        await _gameRepository.UpdateAsync(game);
        await _gameRepository.SaveChangesAsync();

        return player.Id;
    }

    private List<PlayerColor> GetAvailableColors(ColorFillGame.Domain.Entities.Game game)
    {
        var usedColors = game.Players
            .Where(p => p.Color != null)
            .Select(p => p.Color!)
            .ToList();

        var allColorNames = PlayerColor.GetAvailableColors();
        return allColorNames
            .Select(name => new PlayerColor(name))
            .Where(color => !usedColors.Contains(color))
            .ToList();
    }
}